#!/usr/bin/env python
# Create: 2018/12/17
__author__ = '749B'
"""自定义过滤选项"""

import datetime
import re

from django.contrib import admin
from django.contrib.admin.filters import DateFieldListFilter
from django.db import models
from django.utils import timezone
from django.utils.translation import gettext_lazy as _

from log_audit.models import LogProcessing


# 可以改成类装饰器： https://www.jianshu.com/p/dd983ecc1104
def process_distinct(func):  # 最外层的函数名字换成你装饰器的名字
    def wrapper(*args, **kwargs):
        # 执行前，不处理
        res = func(*args, **kwargs)  # 这句不变
        # 执行后，加工
        qs_dic = {}
        qs_list = []
        for p in res:
            p = p[0]
            re_search = re.search("^(.+)\[(\d{1,5})\]:$", p)
            if re_search:
                process, port = re_search.groups()
                if process in qs_dic:
                    if port < qs_dic[process][0]:
                        qs_dic[process][0] = port
                    elif port > qs_dic[process][1]:
                        qs_dic[process][1] = port
                else:
                    qs_dic.setdefault(process, [port, port])
            else:
                qs_list.append((p,) * 2)
        for k, v in qs_dic.items():
            if v[0] == v[1]:
                qs_list.append(("%s[%s]:" % (k, v[0]),) * 2)
            else:
                qs_list.append(("%s[" % k, "%s[%s-%s]:" % (k, v[0], v[1])))
        return (i for i in qs_list)
    return wrapper


# 对 LogProcessing 表的 auto_tag 字段做过滤
class LogProcessingAutoTagListFilter(admin.SimpleListFilter):
    title = "是否忽略"
    parameter_name = "ignored_tags"

    def lookups(self, request, model_admin):
        return (
            ('no', "未忽略"),  # 包括其他的自动标签和未标记的
            ('yes', "忽略"),
            ('Isnull', "未标记"),
        )

    def queryset(self, request, queryset):
        if self.value() == 'no':
            return queryset.exclude(auto_tag="忽略")
        if self.value() == 'yes':
            return queryset.filter(auto_tag="忽略")
        if self.value() == 'Isnull':
            return queryset.filter(auto_tag__isnull=True)


class LogProcessingListFilter(admin.SimpleListFilter):
    title = 'verbose_name'  # 子类修改这里的2个公有属性即可
    parameter_name = 'last_log__field_name'

    def lookups(self, request, model_admin):
        qs = model_admin.get_queryset(request)
        # 只保留对c_time的过滤规则
        filter_dic = {k: v for k, v in request.GET.items() if k.startswith('c_time')}
        # 主机的过滤也要加进去
        filter_dic.update({k: v for k, v in request.GET.items() if k == 'last_log__host'})
        # 根据get参数，过滤数据，提取显示的数据才有的选项
        qs = qs.filter(**filter_dic)
        qs_set = qs.values_list(self.parameter_name, flat=True).distinct()
        return ((i, i) for i in qs_set)

    def queryset(self, request, queryset):
        if self.value():
            return queryset.filter(**{self.parameter_name: self.value()})


class HostListFilter(LogProcessingListFilter):
    title = '主机名'
    parameter_name = 'last_log__host'

    # lookups方法需要重写，去掉对主机名的过滤
    def lookups(self, request, model_admin):
        qs = model_admin.get_queryset(request)
        # 只保留对c_time的过滤规则
        filter_dic = {k: v for k, v in request.GET.items() if k.startswith('c_time')}
        # 不需要对主机进行过滤
        # 根据get参数，过滤数据，提取显示的数据才有的选项
        qs = qs.filter(**filter_dic)
        qs_set = qs.values_list(self.parameter_name, flat=True).distinct()
        return ((i, i) for i in qs_set)


class SeverityListFilter(LogProcessingListFilter):
    title = '严重等级'
    parameter_name = 'last_log__severity'


class FacilityListFilter(LogProcessingListFilter):
    title = 'facility'
    parameter_name = 'last_log__facility'


class ProcessListFilter(LogProcessingListFilter):
    """下面的ProcessParsedLogListFilter里的方法可以考虑复用过来，
    那样的话，需要重构一下
    加上父类的过滤规则，然后复用合并服务端口号的方法
    """
    title = '子系统'
    parameter_name = 'last_log__process'


class ProcessParsedLogListFilter(admin.SimpleListFilter):
    title = '子系统'
    parameter_name = 'process'

    @process_distinct
    def lookups(self, request, model_admin):
        qs = model_admin.get_queryset(request)
        qs_set = qs.values_list(self.parameter_name, flat=True).distinct()
        return ((i, i) for i in qs_set)

    def queryset(self, request, queryset):
        if self.value():
            return queryset.filter(**{"%s__startswith" % self.parameter_name: self.value()})


# 修改源码进行自定义过滤（list_filter）
class MyDateFieldListFilter(DateFieldListFilter):
    def __init__(self, field, request, params, model, model_admin, field_path):
        """直接把父类的构造方法赋值过来，再修改，避免一些重复的计算"""
        self.field_generic = '%s__' % field_path
        self.date_params = {k: v for k, v in params.items() if k.startswith(self.field_generic)}

        now = timezone.now()
        # When time zone support is enabled, convert "now" to the user's time
        # zone so Django's definition of "Today" matches what the user expects.
        if timezone.is_aware(now):
            now = timezone.localtime(now)

        if isinstance(field, models.DateTimeField):
            today = now.replace(hour=0, minute=0, second=0, microsecond=0)
        else:       # field is a models.DateField
            today = now.date()
        tomorrow = today + datetime.timedelta(days=1)
        if today.month == 12:
            next_month = today.replace(year=today.year + 1, month=1, day=1)
        else:
            next_month = today.replace(month=today.month + 1, day=1)
        next_year = today.replace(year=today.year + 1, month=1, day=1)

        # 计算上次审计的日期
        last_audit_day = LogProcessing.objects.last().c_time
        if isinstance(field, models.DateTimeField):
            last_audit_day = datetime.datetime(
                year=last_audit_day.year, month=last_audit_day.month, day=last_audit_day.day)
            last_audit_day = timezone.make_aware(last_audit_day)

        self.lookup_kwarg_since = '%s__gte' % field_path
        self.lookup_kwarg_until = '%s__lt' % field_path
        self.links = (
            (_('Any date'), {}),
            (_('Today'), {
                self.lookup_kwarg_since: str(today),
                self.lookup_kwarg_until: str(tomorrow),
            }),
            ("上次审计至今", {
                self.lookup_kwarg_since: str(last_audit_day),
                self.lookup_kwarg_until: str(today),
            }),
            (_('Past 7 days'), {
                self.lookup_kwarg_since: str(today - datetime.timedelta(days=7)),
                self.lookup_kwarg_until: str(tomorrow),
            }),
            (_('This month'), {
                self.lookup_kwarg_since: str(today.replace(day=1)),
                self.lookup_kwarg_until: str(next_month),
            }),
            (_('This year'), {
                self.lookup_kwarg_since: str(today.replace(month=1, day=1)),
                self.lookup_kwarg_until: str(next_year),
            }),
        )
        if field.null:
            self.lookup_kwarg_isnull = '%s__isnull' % field_path
            self.links += (
                (_('No date'), {self.field_generic + 'isnull': 'True'}),
                (_('Has date'), {self.field_generic + 'isnull': 'False'}),
            )
        # 下面这句在父类里是运行它父类的构造方法，这里改成直接运行祖父类的构造方法
        super(DateFieldListFilter, self).__init__(field, request, params, model, model_admin, field_path)


